home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Development Platforms / LISP Related / Generalized LISP / Glisp 1.2 / Source files / Interpreter.glisp < prev    next >
Encoding:
Text File  |  1990-08-19  |  58.9 KB  |  2,015 lines  |  [TEXT/CCL ]

  1.  
  2. ~---------------------------------------------------------------------------------------~
  3. ~                Plisp interpreter                    ~
  4. ~---------------------------------------------------------------------------------------~
  5.  
  6. -Mlisp-
  7.  
  8. export(    '(                    ~ functions
  9.     peval papply pcall
  10.     parse parseFile parseString parseList parseStream reparse
  11.     defpfun addRules removeRules getRules sourceLanguage targetLanguage
  12.  
  13.     identifier aDelimiter aNumber aString aType reservedWord nonReservedWord eof
  14.     isNot flush pVariable lhs rhs phs onLeft onRight pWarning pError checkFunction
  15.  
  16.     empty? peek next nextIs? nextAre? failure failed? failureValue?
  17.     plispFunction? leftSide? rightSide?
  18.  
  19.     cat neql nequal nequalp plist pname printc str
  20.  
  21.     pTrace pFullTrace pTrap pUntrace pUnfullTrace pUntrap
  22.  
  23.     literal variable call repeat alternatives beginList endList lisp literals
  24.     branches rewritesTo
  25. ), `:glisp);
  26.  
  27.  
  28. export(    '(                    ~ variables
  29.     `*lisp-readtable* `*glisp-readtable* `*glisp-sexp-readtable*
  30.     `*pstandard-output* `*perror-output* `*ptrace-output*
  31. ), `:glisp);
  32.  
  33.  
  34. export(    '(                    ~ symbols
  35.     \!  \@  \#  \$  \%  \^  \&  \*  \(  \)  \_  \+  \-  \=  \{  \}
  36.     \[  \]  \:  \"  \;  \'  \<  \>  \?  \,  \.  \/  \~  \`  \|  \\
  37.     \:\=    \<\=    \>\=    \/\=
  38.  
  39.     \¡  \™  \£  \¢  \∞  \§  \¶  \•  \ª  \º  \–  \≠  \∑  \´  \®  \†  \¥  \¨  \^  \π
  40.     \“  \‘  \∂  \ƒ  \©  \Δ  \¬  \…  \Ω  \≈  \√  \∫  \µ  \≤  \≥  \÷  \«  \°  \—  \±
  41.     \∏  \”  \’  \  \◊  \¿  \»
  42.     \œ  \ø  \å  \æ  \ç  \ß
  43.     \Œ  \Ø  \Å  \Æ  \Ç
  44.  
  45.     all done
  46. ), `:glisp);
  47.  
  48.  
  49. ~ these get bound by parse when parsing a Plisp file
  50.  
  51. defvar(    !reservedWords,    nil,    "(list) identifiers unquoted on left sides of rules");
  52. defvar(    !nRedefined,    0,    "(integer) number of functions that were redefined");
  53.  
  54.  
  55. ~ these get bound by papply when calling Plisp from Lisp
  56.  
  57. defvar(    !source,    nil,    "(headed list) the current input stream");
  58. defvar(    !savedSources,    nil,    "(stack) for backtracking; a stack because of flush");
  59. defvar(    !sourceStream,    nil,    "(stream/list) not-yet-scanned tail of input stream");
  60. defvar(    !sourceStack,    nil,    "(stack) for managing nested input");
  61. defvar(    !destStack,    nil,    "(stack) for managing nested output");
  62. defvar(    !sideStack,    nil,    "(stack) booleans saying which side of a rule we're on");
  63. defvar(    !sourceLanguage, nil,    "(symbol) the language in which the input is written");
  64. defvar(    !targetLanguage, nil,    "(symbol) the language defined by the input, if any");
  65. defvar(    !farthestIndex,    0,    "(integer) index of farthest point reached in input");
  66. defvar(    !farthestTail,    nil,    "(list) remaining input at last advance of list input");
  67. defvar(    !farthestFailure, nil,    "(string) failure message at farthest point in input");
  68. defvar(    !farthestFunction, nil,    "(symbol) name of function containing !farthestFailure");
  69. defvar(    !varNames,    nil,    "(association list) for translating :variable names");
  70. defvar(    !pIndent,    0,    "(integer) indentation level for trace output");
  71. defvar(    !currentPlispFunction,
  72.             nil,    "(symbol) name of current Plisp function--for tracing");
  73.  
  74. global    `*readtable* ;        ~(readtable) the current readtable in effect
  75.  
  76.  
  77. ~these get bound at beginning of every Plisp function
  78.  
  79. defvar(    !dest,        nil,    "(headed list) current output stream");
  80. defvar(    !variables,    nil,    "(association list) the current :variable bindings");
  81. defvar(    !inRepeat,    nil,    "(t, nil) are we inside a repeat [ ]* ?");
  82.  
  83.  
  84. ~ these get bound at the beginning of every repeat (!inRepeat also gets rebound then)
  85.  
  86. defvar(    !repeatCount,    0,    "(integer) number of times through the current repeat");
  87.  
  88.  
  89. ~ miscellaneous globals
  90.  
  91. defvar(    !pTrace,        nil,    "(t, nil) are Plisp functions being traced?");
  92.  
  93. defvar(    `*lisp-readtable*,    nil,    "(readtable) standard Common Lisp definition");
  94. defvar(    `*glisp-readtable*,    nil,    "(readtable) Glisp definition");
  95. defvar(    `*glisp-sexp-readtable*, nil,    "(readtable) Glisp definition in s-expressions");
  96.  
  97. defvar(    `*pstandard-output*,    nil,    "(stream) the standard Glisp output stream");
  98. defvar(    `*ptrace-output*,    nil,    "(stream) Glisp stream for tracing");
  99. defvar(    `*perror-output*,    nil,    "(stream) Glisp stream for errors");
  100.  
  101.  
  102. ~ Common Lisp globals
  103.  
  104. global    `*trace-print-length* := 10,    ~(integer) length of traced argument/value lists
  105.     `*trace-print-level*  := 5,    ~(integer) depth of traced argument/value lists
  106.     `*print-abbreviate-quote* ;    ~(t, nil) turn (quote x) into 'x ?
  107.  
  108.  
  109. ~ Common Lisp stream index and end-of-stream indicator
  110.  
  111. proclaim('`(object-variable  ccl::index  ccl::end));
  112.  
  113.  
  114. defmacro failed? (ex) =
  115.     ~ predicate: true iff the expression fails (i.e. calls failure()) when it is
  116.     ~ executed.  This allows one to call functions which may fail and still maintain
  117.     ~ control when the failure happens.  Example:
  118.     ~    if failed?(w := foo(x, y, z)) then <something> else <something else>
  119.  
  120.     `(catch !failure ,ex nil) ;
  121.  
  122.  
  123. defsetf(vEval, vSet);        ~ :x := y  ->  (setf (vEval n) y)  ->  (vSet n y)
  124.  
  125.  
  126. ~---------------------------------------------------------------------------------------~
  127. ~                Plisp "op code" interpreter                ~
  128. ~---------------------------------------------------------------------------------------~
  129. ~
  130. ~ There are 9 basic operators that can occur in rules:
  131. ~
  132. ~    literal        (literal <atom>)
  133. ~    variable    (variable <number> [t <pattern>])
  134. ~    call        (call <identifier> [<pattern>] [t])
  135. ~    repeat        (repeat <number> <number> <pattern> [<pattern>])
  136. ~    alternatives    (alternatives <number> <pattern> ... <pattern>)
  137. ~    beginList    (beginList)
  138. ~    endList        (endList)
  139. ~    lisp        (lisp [if|do|value] <s-expression> ...)
  140. ~    rewritesTo    (rewritesTo)
  141. ~
  142. ~ plus 2 that result from the combination of rules:
  143. ~
  144. ~    literals    (literals (<atom> <item>...<item>) ... (<atom> <item>...<item>))
  145. ~    branches    (branches <pattern> ... <pattern>)
  146. ~
  147. ~ These are implemented by "operation codes" that carry out the pattern matching.
  148. ~ All op codes are "predicates", where false is represented by calling failure().
  149. ~ If any op code in a pattern fails, the whole pattern fails.
  150. ~ Most op codes (and therefore patterns) can fail on the left or right side of a rule.
  151.  
  152.  
  153. defun slVariable (var) =
  154.     ~ single valued variable on left side of a rule:  :x -> or .. ->
  155.     ~ unbound :x fails only if there is no input
  156.     ~ bound :x fails if the input doesn't match its value
  157.  
  158.     if vBound?(var) then                ~ :x has a value
  159.         begin
  160.         new value := vEval(var, not !inRepeat);
  161.         if !inRepeat and listp(value) then        ~ [:x]*
  162.             if !repeatCount > length(value) then    ~ add to repeat list
  163.                 vSet(var, addValue(value, !repeatCount, next()))
  164.             else nextIs?(value[!repeatCount]) or failure(":" cat var)
  165.         else nextIs?(value) or failure(":" cat var);    ~ :x
  166.         end
  167.     else if !inRepeat then                ~ [:x]*, :x unbound
  168.         if empty?() then failure(":" cat var)    ~ no input left
  169.         else vSet(var, {next()})        ~ first time through
  170.     else if empty?() then failure(":" cat var)    ~ no input left
  171.     else vSet(var, next());                ~ :x unbound
  172.  
  173.  
  174. defun srVariable (var) =
  175.     ~ single valued variable on right side of a rule:  -> :x or -> ..
  176.     ~ :x can fail only if it is in a repeat
  177.  
  178.     begin
  179.     new value :=
  180.         if vBound?(var) then vEval(var, nil)    ~ has a value
  181.         else vSet(var, nil);            ~ no value
  182.     if !inRepeat and listp(value) then        ~ [:x]*
  183.         if !repeatCount > length(value) then    ~ var exhausted
  184.             failure(":" cat var)
  185.         else !dest := !dest xCons value[!repeatCount]
  186.     else !dest := !dest xCons value;        ~ :x
  187.     end;
  188.  
  189.  
  190. defun mlVariable (var, takeAllInput, firstTime) =
  191.     ~ multiple valued variable on left side of a rule:  ::x -> or ... ->
  192.     ~ unbound ::x fails only if it runs out of input and its pattern still
  193.     ~    hasn't matched
  194.     ~ bound ::x fails if the input doesn't match its value or its pattern
  195.     ~    doesn't match
  196.  
  197.     if vBound?(var) then                ~ ::x has a value
  198.         begin
  199.         new value := vEval(var, firstTime and not !inRepeat);
  200.         if not listp(value) then
  201.             pError("the value of ::", var, " is not a list: ", value)
  202.         else if !inRepeat then                ~ [::x]*
  203.             if !repeatCount > length(value) then    ~ add a value
  204.                 vSet(var, addValue(value, !repeatCount,
  205.                     value[!repeatCount] nconc {next()}))
  206.             else nextAre?(value[!repeatCount]) or failure("::" cat var)
  207.         else if firstTime then nextAre?(value) or failure("::" cat var)
  208.         else vset(var, value nconc {next()});    ~ add a value
  209.         end
  210.     else if !inRepeat then                ~ unbound [::x]*
  211.         if empty?() then failure("::" cat var)
  212.         else vSet(var, {next()})        ~ first time through
  213.     else if takeAllInput then            ~ unbound ::x) or ::x ->
  214.         if null !sourceStream then        ~ optimization
  215.             vSet(var, cdr !source) also
  216.             !source := xNew()
  217.         else pError("shouldn't happen")        ~ *** ??
  218.     else vSet(var, {next()});            ~ unbound ::x
  219.  
  220.  
  221. defun mrVariable (var) =
  222.     ~ multiple valued variable on right side of a rule:  -> ::x or -> ...
  223.     ~ ::x can fail only if it is in a repeat
  224.  
  225.     begin
  226.     new value :=
  227.         if vBound?(var) then vEval(var, nil)    ~ ::x has a value
  228.         else vSet(var, nil);            ~ ::x is unbound
  229.     if not listp(value) then
  230.         pError("the value of ::", var, " is not a list: ", value)
  231.     else if !inRepeat then                ~ [::x]*
  232.         if !repeatCount > length(value) then    ~ value exhausted
  233.             failure("::" cat var)
  234.         else !dest := !dest xAppend value[!repeatCount]
  235.     else !dest := !dest xAppend value;        ~ ::x
  236.     end;
  237.  
  238.  
  239. defun lCall (fn, args, many) =
  240.     ~ function call on left side of a rule:  <fn> ->
  241.     ~ can fail if any argument item fails or no rule matches
  242.  
  243.     begin
  244.     new value, !currentPlispFunction := fn;
  245.     value :=
  246.         if plispFunction?(fn) then    ~ Plisp function
  247.             !source := args xPrepend !source also
  248.             apply(fn, nil)
  249.         else                ~ Lisp function
  250.             {apply(fn, args)};    ~ add an extra set of parentheses
  251.     if null value or car(value) eq !noValue then
  252.         nil                ~ function returned no value
  253.     else if many then
  254.         for v in reverse(value) do !source := v xPrepend !source
  255.     else !source := value xPrepend !source;
  256.     end;
  257.  
  258.  
  259. defun rCall (fn, args, many) =
  260.     ~ function call on right side of a rule:  -> <fn>
  261.     ~ can fail if any argument item fails or no rule matches
  262.  
  263.     begin
  264.     new value, !currentPlispFunction := fn;
  265.     if plispFunction?(fn) then        ~ Plisp function
  266.         !source := args xPrepend !source also
  267.         value := apply(fn, nil)
  268.     else                    ~ Lisp function
  269.         value := {apply(fn, args)};    ~ add an extra set of parentheses
  270.     if null value or car(value) eq !noValue then
  271.         nil                ~ function returned no value
  272.     else if many then
  273.         for v in value do !dest := !dest xAppend v
  274.     else !dest := !dest xAppend value;
  275.     end;
  276.  
  277.  
  278. defun repeatMax (var) =
  279.     ~ computes the maximum number of times to go through the repeat
  280.  
  281.     if vBound?(var) then vEval(var, nil)
  282.     else nil;
  283.  
  284.  
  285. defun repeatStop? (max) =
  286.     ~ predicate: true iff the number of repeat iterations exceeds the maximum
  287.     ~ max = nil means there is no maximum
  288.  
  289.     begin
  290.     !repeatCount := !repeatCount + 1;
  291.     return max and !repeatCount > max;
  292.     end;
  293.  
  294.  
  295. defun repeatSet (var, min) =
  296.     ~ makes sure the repeat executed at least min times, then sets the repeat's
  297.     ~ control variable to the number of iterations
  298.  
  299.     begin
  300.     !repeatCount := !repeatCount - 1;    ~ didn't complete the last iteration
  301.     if not vBound?(var) then
  302.         vSet(var, !repeatCount);    ~ record the number of iterations
  303.     if !repeatCount < min or !repeatCount < vEval(var, nil) then
  304.         ~ didn't go through enough times
  305.         failure(max(min, vEval(var, nil)) cat " iterations in a repeat [...]*");
  306.     end;
  307.  
  308.  
  309. defun altCheck (var) =
  310.     ~ makes sure that an alternative control variable is bound
  311.  
  312.     if vBound?(var) then vEval(var, nil)
  313.     else pError("unmatched alternatives on the right side of a rule");
  314.  
  315.  
  316. defun lBeginList () =
  317.     ~ beginning of list structure; starts a nested source list
  318.  
  319.     if listp(peek()) then
  320.         pushSource(next())
  321.     else if nextIs?(!lParen) then
  322.         pushSource(readSourceList())
  323.     else failure("(");
  324.  
  325.  
  326. defun rBeginList () =
  327.     ~ beginning of list structure; starts a nested destination list
  328.     ~ this could be expanded inline if we wish
  329.  
  330.     push(!dest, !destStack) also
  331.     !dest := xNew();
  332.  
  333.  
  334. defun lEndList () =
  335.     ~ end of list structure; ends one level of nested source
  336.  
  337.     if empty?() and !sourceStack then
  338.         popSource()
  339.     else failure(")");
  340.  
  341.  
  342. defun rEndList () =
  343.     ~ end of list structure; ends one level of nested destination
  344.     ~ this could be expanded inline if we wish
  345.  
  346.     !dest := xCons(pop(!destStack), cdr !dest);
  347.  
  348.  
  349. ~---------------------------------------------------------------------------------------~
  350. ~                Other parsing functions                    ~
  351. ~---------------------------------------------------------------------------------------~
  352.  
  353. defun beginPlispFunction (fn) =
  354.     ~ entering a plisp function
  355.  
  356.     if !pTrace and (fn.pTrace or fn.pFullTrace) then
  357.         begin
  358.         !pIndent := !pIndent + 1;
  359.         indentedPrintc("Calling <", fn, ">");
  360.         if fn.pFullTrace then
  361.             begin
  362.             new rules := getRules(fn);
  363.             indentedPrintc("pattern: ");
  364.             if null rules then princ(nil, `*ptrace-output*)
  365.             else uncompilePattern(rules, `*trace-print-length*);
  366.             end;
  367.         indentedPrintc("input: ");
  368.         princList(rest !source, `*ptrace-output*);
  369.         terpri(`*ptrace-output*);
  370.         if fn.pTrap then pbreak();
  371.         end;
  372.  
  373.  
  374. defun endPlispFunction (fn) =
  375.     ~ exiting a plisp function
  376.  
  377.     begin
  378.     if !pTrace and (fn.pTrace or fn.pFullTrace) then
  379.         begin
  380.         indentedPrintc("<", fn, "> -> ");
  381.         princList(rest !dest, `*ptrace-output*);
  382.         terpri(`*ptrace-output*);
  383.         if fn.pTrap then pbreak();
  384.         !pIndent := !pIndent - 1;
  385.         end;
  386.     return cdr !dest;            ~ value of the function
  387.     end;
  388.  
  389.  
  390. defun setDecisionPoint () =
  391.     ~ sets a decision point: 7 items are saved for backtracking
  392.  
  393.     begin
  394.     push( !pIndent,        !savedSources);
  395.     push( cdr !source,    !savedSources);
  396.     push( !sourceStream,    !savedSources);
  397.     push( !sourceStack,    !savedSources);
  398.     push( cdr !dest,    !savedSources);
  399.     push( !destStack,    !savedSources);
  400.     push( !variables,    !savedSources);
  401.     end;
  402.  
  403.  
  404. defun restoreDecisionPoint () =
  405.     ~ restores the state at the last decision point
  406.  
  407.     begin
  408.     !pIndent    := !savedSources[7];
  409.     !source        := xHead(!savedSources[6]);
  410.     !sourceStream    := !savedSources[5];
  411.     !sourceStack    := !savedSources[4];
  412.     !dest        := xHead(!savedSources[3]);
  413.     !destStack    := !savedSources[2];
  414.     !variables    := !savedSources[1];
  415.     return t;                ~ value must be true
  416.     end;
  417.  
  418.  
  419. defun deleteDecisionPoint () =
  420.     ~ deletes the last decision point: 7 saved items
  421.  
  422.     begin
  423.     !savedSources := nthcdr(7, !savedSources);
  424.     return t;                ~ value must be true
  425.     end;
  426.  
  427.  
  428. ~---------------------------------------------------------------------------------------~
  429. ~                Internal subroutines                    ~
  430. ~---------------------------------------------------------------------------------------~
  431.  
  432. defun pushSource (newsource) =
  433.     ~ manages nested input.
  434.     ~ newsource must be a list.
  435.     ~ after pushSource, !source is a list of all the input at the new level,
  436.     ~ and !sourceStream is nil
  437.  
  438.     begin
  439.     push(rest !source, !sourceStack);
  440.     push(!sourceStream, !sourceStack);
  441.     !source := xHead(newsource);
  442.     !sourceStream := nil;
  443.     end;
  444.  
  445.  
  446. defun popSource () =
  447.     ~ manages nested input
  448.  
  449.     !sourceStream := pop(!sourceStack) also
  450.     !source := xHead(pop(!sourceStack));
  451.  
  452.  
  453. defun vBound? (var) =
  454.     ~ predicate: true iff the plisp variable var has already been bound
  455.     ~ analogous to boundp(var), but uses the !variables alist
  456.  
  457.     assoc(var, !variables);
  458.  
  459.  
  460. defun vEval (var, &optional traceit := t) =
  461.     ~ gets the value of the plisp variable var
  462.     ~ analogous to eval(var), but uses the !variables alist
  463.     ~ all Plisp variables are effectively initialized to nil
  464.  
  465.     begin
  466.     new x;
  467.     if null x := assoc(var, !variables) then
  468.         x := var cons nil;
  469.     if !pTrace and !currentPlispFunction.pFullTrace and traceit then
  470.         indentedPrintc(":", var, " = ", cdr x) also
  471.         terpri(`*ptrace-output*);
  472.     return cdr x;
  473.     end;
  474.  
  475.  
  476. defun vSet (var, val, &optional traceit := t) =
  477.     ~ sets the value of the plisp variable var to val
  478.     ~ analogous to set(var, val), but uses the !variables alist
  479.  
  480.     begin
  481.     !variables := (var cons val) cons remove(assoc(var, !variables), !variables);
  482.         ~ don't use rplaca, so that variables can be backtracked
  483.     if !pTrace and !currentPlispFunction.pFullTrace and traceit then
  484.         indentedPrintc(":", var, " := ", val) also
  485.         terpri(`*ptrace-output*);
  486.     return val;
  487.     end;
  488.  
  489.  
  490. defun addValue (l, i, value) =
  491.     ~ returns the list 'l' with the 'i'th location replaced with 'value'.
  492.     ~ does not use rplaca, so that 'l' can be backtracked.
  493.     ~ 'l' will be extended with nils if its length is currently less than 'i'.
  494.     ~ 'i' is assumed to be a positive integer.
  495.  
  496.     if i = 1 then value cons cdr(l)
  497.     else car(l) cons addValue(cdr(l), i-1, value);
  498.  
  499.  
  500. defun canonicalName (var, onLeft, &aux x) =
  501.     ~ maps symbolic names into numeric indicies to facilitate rule merging
  502.     ~ e.g. :x :y :z -> 1 2 3
  503.     ~ handles generic items such as [] and ..., which are matched by position
  504.     ~ var=nil is a wild card used to generate a new name
  505.  
  506.     if var member '(\. \[ \|) then
  507.         if onLeft then                ~ create a name for the item
  508.             newName(var)
  509.         else if x := assoc(var, !varNames) then    ~ variable has already occurred
  510.             car(x) := gensym() also        ~ don't reuse it;
  511.             cdr(x)                ~ instead, bind by position
  512.         else if var eq '\. then
  513.             pWarning("too many ...'s on the right side of a rule") also
  514.             newName(gensym())
  515.         else newName(gensym())            ~ []* only on right side are ok
  516.     else if x := assoc(var, !varNames) then        ~ variable has already occurred
  517.         cdr(x)                    ~ use its existing name
  518.     else if onLeft then                ~ create a name for the variable
  519.         newName(var)
  520.     else pWarning("unbound variable on the right side of a rule: ", var) also
  521.         newName(var);
  522.  
  523.  
  524. defun newName (var) =
  525.     ~ creates a new canonical name (i.e. number) for a variable
  526.  
  527.     cdar(!varNames := (var cons length(!varNames) + 1) cons !varNames);
  528.  
  529.  
  530. defun restoreName (var, val) =
  531.     ~ restores the name for a canonical value, e.g. <restoreName '[ :n>
  532.  
  533.     begin
  534.     for pair in !varNames do nil until
  535.         if cdr(pair) = val then car(pair) := var;
  536.     return !noValue;
  537.     end;
  538.  
  539.  
  540. defun recordMessage (message, override) =
  541.     ~ records the error message for the farthest failure in the input stream
  542.  
  543.     if message
  544.         and (null !farthestFailure or override)
  545.         and not xNull?(!source)
  546.         and (null cddr !source or !farthestTail eq rest !source)
  547. ~* (?) *    and null !dest            ~ implies on left side of rule
  548.     then
  549.         !farthestFailure  := message also
  550.         !farthestFunction := !currentPlispFunction;
  551.  
  552.  
  553. defun princAtom (name, &optional stream := `*pstandard-output*) =
  554.     ~ princs an atom followed by a space
  555.  
  556.     princ(name, stream) also
  557.     princ(" ", stream);
  558.  
  559.  
  560. defun princList (l, &optional stream := `*ptrace-output*) =
  561.     ~ princs list elements separated by spaces
  562.  
  563.     for x in l do
  564.         princAtom(x, stream);
  565.  
  566.  
  567. defun readSourceList () =
  568.     ~ replaces '(' ... ')' in the input with a list;
  569.     ~ note: this reads only LISTS, not DOTTED PAIRS, since I don't know how to tell
  570.     ~ (a . b) from (a \. b)!
  571.     ~ note: this is also unable to distinguish \( from ( and \) from ) in the input!
  572.  
  573.     let (`*readtable* :=
  574.             if `*readtable* eq `*glisp-readtable* then
  575.                 `*glisp-sexp-readtable*
  576.             else `*readtable*) =
  577.         if empty?() or nextIs?(!rParen) then nil
  578.  
  579. ~ *** don't know how to make this work: ***
  580. ~    else if nextIs?('\.) then
  581. ~            prog1(next(), if not nextIs?(!rParen) then
  582. ~                error("illegal s-expression"))
  583.  
  584.         else next() cons readSourceList();
  585.  
  586.  
  587. defun readSExpression (stream) =
  588.     ~ reads a Plisp s-expression from a stream.
  589.     ~ The structure of a Plisp s-expression is the same as in Lisp, but each atom
  590.     ~ in it conforms to Plisp's syntax (i.e. what is a letter, etc.)
  591.  
  592.     let (`*readtable* :=
  593.             if `*readtable* eq `*glisp-readtable* then
  594.                 `*glisp-sexp-readtable*
  595.             else `*readtable*) =
  596.         `read-preserving-whitespace(stream, nil, !eof, nil);
  597.  
  598.  
  599. ~defun readAtom (stream) =
  600. ~    ~ reads a single atom from a stream.  This is exactly like read, except when the
  601. ~    ~ next thing in the input is a left parenthesis.
  602. ~
  603. ~    if `peek-char(nil, stream, nil, !eofchar, t) `char= `#\( then
  604. ~        `read-char(stream, nil, !eofchar, t) also
  605. ~        !lParen
  606. ~    else `read-preserving-whitespace(stream, nil, !eof, nil);
  607.  
  608.  
  609. defun lispRead (&optional stream, eofp, eofvalue, recursivep) =
  610.     ~ reads an s-expression using the standard Lisp readtable.
  611.     ~ this implements a principal interface to Lisp from Mlisp and Plisp
  612.  
  613.     let (`*readtable* := `*lisp-readtable*) =
  614.         if consp(stream) then xpop(stream)
  615.         else read(stream, eofp, eofvalue, recursivep);
  616.  
  617.  
  618. ~---------------------------------------------------------------------------------------~
  619. ~                Defining rewrite functions                ~
  620. ~---------------------------------------------------------------------------------------~
  621.  
  622. defmacro defpfun (name, args, body, rules) =
  623.     ~ defines a new Plisp function from scratch; analogous to defun and defmacro.
  624.     ~ the rules should be already merged into a rule tree;
  625.     ~ the body should be the expansion (into ordinary Lisp) of the rule tree
  626.  
  627.     `(&defpfun ',name ',args ',body ',rules);
  628.  
  629.  
  630. defun &defpfun (name, args, body, rules) =
  631.     begin
  632.     name.pRules := rules;            ~ save the unexpanded rules
  633.     name.pFunction := t;            ~ mark it as a Plisp function
  634.     eval {'defun, name, args, body};    ~ define the function
  635.     end;
  636.  
  637.  
  638. defun addRules (name, rules, appearanceOrder) =
  639.     ~ adds rules to an existing Plisp function.
  640.     ~ gets the existing rules at EVAL time, not at TRANSLATE time
  641.  
  642.     begin
  643.     eval papply('expandRules, {name,
  644.         papply('mergeRules, {reverse(rules), getRules(name), appearanceOrder})});
  645.     return !noValue;
  646.     end;
  647.  
  648.  
  649. defun removeRules (name, rules) =
  650.     ~ removes rules from an existing Plisp function
  651.  
  652.     begin
  653.     new tree := getRules(name);
  654.     for rule in rules do
  655.         tree := papply('removeRule, {lhsOnly(rule), tree});
  656.     eval papply('expandRules, {name, tree});
  657.     return !noValue;
  658.     end;
  659.  
  660.  
  661. defun getRules (name) =
  662.     ~ returns the rules for an existing Plisp function, or nil if it doesn't exist
  663.  
  664.     name.pRules;
  665.  
  666.  
  667. defun lhsOnly (rule) =
  668.     ~ returns the left hand side of a rule
  669.  
  670.     if null rule then nil
  671.     else if car(rule) equal '(rewritesTo) then {car(rule)}
  672.     else car(rule) cons lhsOnly(cdr rule);
  673.  
  674.  
  675. defun linearMatch (l1, l2) =
  676.     ~ tests for a simple rule match
  677.  
  678.     l1 equalp firstN(length(l1), l2);
  679.  
  680.  
  681. defun firstN (n, l) =
  682.     ~ returns a list of the first n elements of a list
  683.  
  684.     if n < 1 or null l then nil
  685.     else car(l) cons firstN(n-1, cdr l);
  686.  
  687.  
  688. defun makeReservedWord (word) =
  689.     ~ makes 'word' be a reserved word in the current target language.
  690.     ~ only adds words (identifiers) that occur on the left sides of rules
  691.  
  692.     begin
  693.     if !targetLanguage and leftSide?() then
  694.         !reservedWords := word adjoin !reservedWords;
  695.     return word;
  696.     end;
  697.  
  698.  
  699. defun reservedWords () =
  700.     ~ returns a sorted list of the reserved words collected for a target language
  701.  
  702.     if !targetLanguage then
  703.         {'declareReservedWords,
  704.             {'quote, !targetLanguage},
  705.             {'quote, sort(!reservedWords, function(`string-lessp))}}
  706.     else !noValue;
  707.  
  708.  
  709. defun declareReservedWords (language, words) =
  710.     ~ makes each word in a list of words be a reserved word in a language
  711.  
  712.     begin
  713.     for word in words do            ~ mark each word with the language name
  714.         word.(language) := t;
  715.     language.reservedWords := words;    ~ save the word list
  716.     export(words);                ~ export the words from current package
  717.     export({language});            ~ export the language name too
  718.     end;
  719.  
  720.  
  721. defun addReservedWords (language, words) =
  722.     ~ adds reserved words to an existing language
  723.  
  724.     begin
  725.     new l := language.reservedWords;
  726.     for word in words do            ~ mark each word with the language name
  727.         word.(language) := t also
  728.         l := word adjoin l;        ~ add it to the word list
  729.     language.reservedWords := sort(l, function(`string-lessp));
  730.     export(words);                ~ export the words from current package
  731.     end;
  732.  
  733.  
  734. defun sourceLanguage (language) =
  735.     ~ switches source languages; asserts that the following input is in that language
  736.  
  737.     !sourceLanguage := language also
  738.     !noValue;
  739.  
  740.  
  741. defun targetLanguage (language) =
  742.     ~ switches target languages; all unquoted literal identifiers on the left sides
  743.     ~ of rules will now be declared to be reserved words in that language
  744.  
  745.     !targetLanguage := language also
  746.     !noValue;
  747.  
  748.  
  749. ~---------------------------------------------------------------------------------------~
  750. ~                Headed list routines                    ~
  751. ~---------------------------------------------------------------------------------------~
  752. ~
  753. ~ headed list (a b c) =
  754. ~
  755. ~    [ • | •-]--> [ a | •-]--> [ b | •-]--> [ c | / ]
  756. ~      |                                 |
  757. ~      --------------------------------->|
  758. ~
  759. ~ empty headed list () =
  760. ~
  761. ~   -->    [ • | / ]
  762. ~   |     |
  763. ~   |<-----
  764.  
  765.  
  766. defun xHead (l) =
  767.     ~ converts the list l into a headed list
  768.  
  769.     if consp(l) then last(l) cons l
  770.     else let (hl := l cons nil) = car(hl) := hl also hl;
  771.  
  772.  
  773. defun xNew () =
  774.     ~ creates an empty headed list (an optimization for xHead(nil))
  775.  
  776.     let (hl := nil cons nil) = car(hl) := hl also hl;
  777.  
  778.  
  779. defun xNull? (hl) =
  780.     ~ predicate: true iff hl is the empty headed list
  781.  
  782.     null cdr(hl);
  783.  
  784.  
  785. defun xCons (hl, x) =
  786.     ~ conses onto the end of a headed list
  787.  
  788.     cdar(hl) := x cons nil also
  789.     car(hl) := cdar(hl) also
  790.     hl;
  791.  
  792.  
  793. defun xAppend (hl, l) =
  794.     ~ appends onto the end of a headed list
  795.  
  796.     if null l then hl
  797.     else xAppend(hl xCons car(l), cdr(l));
  798.  
  799.  
  800. defun xPrepend (l, hl) =
  801.     ~ destructively appends a list onto the front of a headed list
  802.  
  803.     if null l then hl
  804.     else progn(if xNull?(hl) then car(hl) := last(l) else cdr(last(l)) := cdr(hl),
  805.         cdr(hl) := l,
  806.         hl);
  807.  
  808.  
  809. defun xPop (hl) =
  810.     ~ pops the first element of a headed list
  811.  
  812.     if null cddr(hl) then
  813.         prog1(cadr(hl), cdr(hl) := cddr(hl), car(hl) := hl)
  814.     else prog1(cadr(hl), cdr(hl) := cddr(hl));
  815.  
  816.  
  817. ~---------------------------------------------------------------------------------------~
  818. ~                Tracing routines                    ~
  819. ~---------------------------------------------------------------------------------------~
  820.  
  821. defmacro pTrace (&rest pfunctions) =
  822.     ~ traces an (unquoted) list of plisp functions
  823.     ~ e.g. (pTrace foo bar zap ...)
  824.  
  825.     `(&pTrace ',pfunctions);
  826.  
  827.  
  828. defmacro pFullTrace (&rest pfunctions) =
  829.     ~ "full traces" an (unquoted) list of plisp functions
  830.     ~ full tracing generates more detailed output than tracing
  831.     ~ e.g. (pFullTrace foo bar zap ...)
  832.  
  833.     `(&pFullTrace ',pfunctions);
  834.  
  835.  
  836. defmacro pTrap (&rest pfunctions) =
  837.     ~ traps an (unquoted) list of plisp functions
  838.     ~ trapping generates the same detailed output as full tracing, and in addition
  839.     ~ breaks on every entry and exit from a trapped function
  840.     ~ e.g. (pTrap foo bar zap ...)
  841.  
  842.     `(&pTrap ',pfunctions);
  843.  
  844.  
  845. defmacro pUntrace (&rest pfunctions) =
  846.     ~ untraces an (unquoted) list of plisp functions
  847.     ~ e.g. (pUntrace foo bar zap ...)
  848.  
  849.     `(&pUntrace ',pfunctions);
  850.  
  851.  
  852. defmacro pUnfullTrace (&rest pfunctions) =
  853.     ~ untraces an (unquoted) list of plisp functions
  854.     ~ e.g. (pUnfullTrace foo bar zap ...)
  855.  
  856.     `(&pUntrace ',pfunctions);
  857.  
  858.  
  859. defmacro pUntrap (&rest pfunctions) =
  860.     ~ untraces an (unquoted) list of plisp functions
  861.     ~ e.g. (pUntrap foo bar zap ...)
  862.  
  863.     `(&pUntrace ',pfunctions);
  864.  
  865.  
  866. defun &pTrace (pfunctions) =
  867.     if null pfunctions then
  868.         !pTrace := t also
  869.         'all.traceList
  870.     else &pUntrace(pfunctions) also        ~ first reset their previous state
  871.         !pTrace := t also
  872.         for pfn in pfunctions collect    ~ then mark them to be traced
  873.             {if plispFunction?(pfn) then
  874.                 pfn.pTrace := t also
  875.                 'all.traceList := pfn cons 'all.traceList also
  876.                 pfn
  877.             else nil};
  878.  
  879.  
  880. defun &pFullTrace (pfunctions) =
  881.     if null pfunctions then
  882.         !pTrace := t also
  883.         'all.traceList
  884.     else &pUntrace(pfunctions) also        ~ first reset their previous state
  885.         !pTrace := t also
  886.         for pfn in pfunctions collect    ~ then mark them to be fully traced
  887.             {if plispFunction?(pfn) then
  888.                 pfn.pFullTrace := t also
  889.                 'all.traceList := pfn cons 'all.traceList also
  890.                 pfn
  891.             else nil};
  892.  
  893.  
  894. defun &pTrap (pfunctions) =
  895.     if null pfunctions then
  896.         !pTrace := t also
  897.         'all.traceList
  898.     else &pUntrace(pfunctions) also        ~ first reset their previous state
  899.         !pTrace := t also
  900.         for pfn in pfunctions collect    ~ then mark them to be trapped
  901.             {if plispFunction?(pfn) then
  902.                 pfn.pFullTrace := t also
  903.                 pfn.pTrap := t also
  904.                 'all.traceList := pfn cons 'all.traceList also
  905.                 pfn
  906.             else nil};
  907.  
  908.  
  909. defun &pUntrace (pfunctions) =            ~ used for untracing and untrapping
  910.     begin
  911.     new value;
  912.     if null pfunctions or pfunctions equal '(all) then
  913.         pfunctions := reverse('all.traceList);
  914.     value := for pfn in pfunctions collect
  915.         {if pfn.pTrace or pfn.pFullTrace or pfn.pTrap then
  916.             pfn.pTrace := pfn.pFullTrace := pfn.pTrap := nil also
  917.             'all.traceList := remove(pfn, 'all.traceList) also
  918.             pfn
  919.         else nil};
  920.     if null 'all.traceList then
  921.         !pTrace := nil;
  922.     return value;
  923.     end;
  924.  
  925.  
  926. defun indentedPrintc (&rest args) =
  927.     ~ a trace routine which prints its arguments indented on a new line
  928.  
  929.     begin
  930.     new `*print-length* := `*trace-print-length*,
  931.         `*print-level* := `*trace-print-level*;
  932.     terpri(`*ptrace-output*);
  933.     for i := 1 to !pIndent - 1 do
  934.         princ(" ", `*ptrace-output*);
  935.     princ("(", `*ptrace-output*);
  936.     princ(!pIndent, `*ptrace-output*);
  937.     princ(") ", `*ptrace-output*);
  938.     for i:= 1 to `*print-length* for a in args do
  939.         if stringp(a) then princ(a, `*ptrace-output*)
  940.         else prin1(a, `*ptrace-output*);
  941.     end;
  942.  
  943.  
  944. defun pBreak () =
  945.     ~ breaks using Lisp's readtable, regardless of what the readtable was set to
  946.  
  947.     begin
  948.     new `*readtable* := `*lisp-readtable* ;
  949.     terpri(`*ptrace-output*);
  950.     break();
  951.     terpri(`*ptrace-output*);
  952.     end;
  953.  
  954.  
  955. ~---------------------------------------------------------------------------------------~
  956. ~                    The uncompiler                    ~
  957. ~---------------------------------------------------------------------------------------~
  958.  
  959. defun uncompilePattern (pattern, n, &optional stream := `*ptrace-output*) =
  960.     ~ turns the translated representation of a pattern back into its plisp form
  961.     ~ only the first n items are uncompiled
  962.  
  963.     if null pattern then n
  964.     else if n <= 0 then princ("...", stream) also 0
  965.     else uncompilePattern(rest pattern,
  966.         uncompileItem(first pattern, n, stream), stream);
  967.  
  968.  
  969. defun uncompileItem (item, n, &optional stream := `*ptrace-output*) =
  970.     ~ this does the work
  971.  
  972.     if atom item then
  973.         princAtom(item, stream) also
  974.         n-1
  975.     else case item[1] of
  976.         begin
  977.         literal:
  978.             ~ (literal <atom>)
  979.             princAtom(item[2], stream) also
  980.             n-1;
  981.         variable:
  982.             ~ (variable <number> [t <pattern>] )
  983.             begin
  984.             princ(if item[3] then "::" else ":", stream);
  985.             princAtom(item[2], stream);
  986.             return    if item[4] then uncompilePattern(item[4], n-1, stream)
  987.                 else n-1;
  988.             end;
  989.         call:
  990.             ~ (call <identifier> [<pattern> [t]])
  991.             begin
  992.             princ(if item[4] then "<<" else "<", stream);
  993.             princ(item[2], stream);
  994.             if item[3] then
  995.                 princ(" ", stream) also
  996.                 n := uncompilePattern(item[3], n-1, stream);
  997.             princ(if item[4] then ">> " else "> ", stream);
  998.             return n;
  999.             end;
  1000.         alternatives:
  1001.             ~ (alternatives var <pattern> ... <pattern>)
  1002.             begin
  1003.             new patterns := cddr(item);
  1004.             princ("[ ", stream);
  1005.             n := uncompilePattern(first patterns, n, stream);
  1006.             if length(patterns) > 2 or second patterns then
  1007.                 for pattern in rest patterns do
  1008.                     princ("| ", stream) also
  1009.                     n := uncompilePattern(pattern, n, stream);
  1010.             princ("] ", stream);
  1011.             return n;
  1012.             end;
  1013.         repeat:
  1014.             ~ (repeat var min <pattern> [<pattern>])
  1015.             begin
  1016.             princ("[ ", stream);
  1017.             n := uncompilePattern(item[4], n, stream);
  1018.             if item[5] then
  1019.                 princ("/ ", stream) also
  1020.                 n := uncompilePattern(item[5], n, stream);
  1021.             princ(if item[3] = 0 then "]* " else "]+ ", stream);
  1022.             return n;
  1023.             end;
  1024.         beginList:
  1025.             ~ (beginList)
  1026.             princ("( ", stream) also
  1027.             n-1;
  1028.         endList:
  1029.             ~ (endList)
  1030.             princ(") ", stream) also
  1031.             n-1;
  1032.         lisp:
  1033.             ~ (lisp [if|do|value] <s-expression> ...)
  1034.             begin
  1035.             princ(if item[2] eq 'value and item[4] then "{{" else "{",
  1036.                 stream);
  1037.             princAtom(item[2], stream);
  1038.             prin1(item[3], stream);
  1039.             princ(if item[2] eq 'value and item[4] then "}} " else "} ",
  1040.                 stream);
  1041.             return n-2;
  1042.             end;
  1043.         `(literals branches):
  1044.             ~ (literals (<atom> <item>...) ... (<atom> <item>...))
  1045.             ~ (branches <pattern> ... <pattern>)
  1046.             begin
  1047.             princ("{", stream);
  1048.             princAtom(item[1], stream);
  1049.             uncompilePattern(item[2], 1, stream);
  1050.             for pattern in cddr(item) do
  1051.                 princ(", ", stream) also
  1052.                 uncompilePattern(pattern, 1, stream);
  1053.             princ("} ", stream);
  1054.             return 0;
  1055.             end;
  1056.         rewritesTo:
  1057.             ~ (rewritesTo)
  1058.             princ("-> ", stream) also
  1059.             n-1;
  1060.         t:
  1061.             ~ shouldn't happen
  1062.             princAtom(item, stream) also
  1063.             n-1;
  1064.         end;
  1065.  
  1066.  
  1067. defun humanize (item) =
  1068.     ~ similar to uncompile, except that it attempts to make translated pattern items
  1069.     ~ even more human readable
  1070.  
  1071.     `string-downcase(humanize1(item));
  1072.  
  1073.  
  1074. defun humanize1 (item) =
  1075.     ~ this does the work
  1076.  
  1077.     if null item then "something"
  1078.     else if atom item then str(item)
  1079.     else case item[1] of
  1080.         begin
  1081.         literal:
  1082.             ~ (literal <atom>)
  1083.             "'" cat item[2] cat "'";
  1084.         variable:
  1085.             ~ (variable <number> [t <pattern>] )
  1086.             (if item[3] then "::" else ":") cat item[2];
  1087.         call:
  1088.             ~ (call <identifier> [<pattern> [t]] )
  1089.             "<" cat item[2] cat ">";
  1090.         alternatives:
  1091.             ~ (alternatives var <pattern> ... <pattern>)
  1092.             begin
  1093.             new s, patterns := cddr(item);
  1094.             s := humanize1(first first patterns);
  1095.             for pattern in rest patterns do
  1096.                 s := s cat " or " cat humanize1(first pattern);
  1097.             return s;
  1098.             end;
  1099.         repeat:
  1100.             ~ (repeat var min <pattern> [<pattern>])
  1101.             "something";
  1102.         beginList:
  1103.             ~ (beginList)
  1104.             "'('";
  1105.         endList:
  1106.             ~ (endList)
  1107.             "')'";
  1108.         lisp:
  1109.             ~ (lisp [if|do|value] <s-expression> ...)
  1110.             case item[2] of
  1111.                 begin
  1112.                 if:    "'" cat item[3] cat "' to be true";
  1113.                 do:    "'" cat item[3] cat "' to not fail";
  1114.                 value:    "the value of '" cat item[3] cat "'";
  1115.                 t:    pWarning("unknown item in a pattern: " cat item)
  1116.                     also "";
  1117.                 end;
  1118.         literals:
  1119.             ~ (literals (<atom> <item>...) ... (<atom> <item>...))
  1120.             begin
  1121.             new s := humanize1({'literal, first item[2]});
  1122.             for pattern in cddr(item) do
  1123.                 s := s cat " or " cat
  1124.                     humanize1({'literal, first pattern});
  1125.             return s;
  1126.             end;
  1127.         branches:
  1128.             ~ (branches <pattern> ... <pattern>)
  1129.             begin
  1130.             new s := humanize1(first item[2]);
  1131.             for pattern in cddr(item) do
  1132.                 s := s cat " or " cat humanize1(first pattern);
  1133.             return s;
  1134.             end;
  1135.         rewritesTo:
  1136.             ~ (rewritesTo)
  1137.             "nothing";
  1138.         t:
  1139.             pWarning("unknown item in a pattern: " cat item) also "";
  1140.         end;
  1141.  
  1142.  
  1143. defun ruleToString (rule) =
  1144.     ~ "uncompiles" a rule, turning it into a string
  1145.  
  1146.     `with-output-to-string(`(out), patternToString(rule, out));
  1147.  
  1148.  
  1149. defun patternToString (pattern, out) =
  1150.     ~ handles embedded patterns
  1151.  
  1152.     if pattern then
  1153.         itemToString(first pattern, out) also
  1154.         for item in rest(pattern) do
  1155.             princ(" ", out) also
  1156.             itemToString(item, out);
  1157.  
  1158.  
  1159. defun itemToString (item, out) =
  1160.     ~ similar to uncompile, except that it puts translated pattern items in a string
  1161.  
  1162.     if null item then
  1163.         nil
  1164.     else if atom item then
  1165.         princ(item, out)
  1166.     else case item[1] of
  1167.         begin
  1168.         literal:
  1169.             ~ (literal <atom>)
  1170.             princ(item[2], out);
  1171.         variable:
  1172.             ~ (variable <number> [t <pattern>])
  1173.             begin
  1174.             princ(if item[3] then "::" else ":", out);
  1175.             princ(item[2], out);
  1176.             if item[4] then
  1177.                 princ(" ", out) also
  1178.                 patternToString(item[4], out);
  1179.             end;
  1180.         call:
  1181.             ~ (call <identifier> [<pattern> [t]])
  1182.             begin
  1183.             princ(if item[4] then "<<" else "<", out);
  1184.             princ(item[2], out);
  1185.             if item[3] then
  1186.                 princ(" ", out) also
  1187.                 patternToString(item[3], out);
  1188.             princ(if item[4] then ">>" else ">", out);
  1189.             end;
  1190.         alternatives:
  1191.             ~ (alternatives var <pattern> ... <pattern>)
  1192.             begin
  1193.             new patterns := cddr(item);
  1194.             princ("[", out);
  1195.             if null patterns then
  1196.                 nil
  1197.             else if length(patterns) = 2 and null patterns[2] then
  1198.                 patternToString(first patterns, out)    ~ optional [pat]
  1199.             else
  1200.                 patternToString(first patterns, out) also
  1201.                 for pattern in rest(patterns) do
  1202.                     princ(" | ", out) also
  1203.                     patternToString(pattern, out);
  1204.             princ("]", out);
  1205.             end;
  1206.         repeat:
  1207.             ~ (repeat var min <pattern> [<pattern>])
  1208.             begin
  1209.             princ("[", out);
  1210.             patternToString(item[4], out);
  1211.             if item[5] then
  1212.                 princ(" / ", out) also
  1213.                 patternToString(item[5], out);
  1214.             princ(if item[3] = 0 then "]*" else "]+", out);
  1215.             end;
  1216.         beginList:
  1217.             ~ (beginList)
  1218.             princ("(", out);
  1219.         endList:
  1220.             ~ (endList)
  1221.             princ(")", out);
  1222.         lisp:
  1223.             ~ (lisp [if|do|value] <s-expression> ...)
  1224.             case item[2] of
  1225.                 begin
  1226.                 if:    princ("{if " cat item[3] cat "}", out);
  1227.                 do:    princ("{do " cat item[3] cat "}", out);
  1228.                 value:    princ(    if item[4] then
  1229.                             "{{value " cat item[3] cat "}}"
  1230.                         else "{value " cat item[3] cat "}",
  1231.                         out);
  1232.                 t:    pWarning("unknown item in a pattern: " cat item)
  1233.                     also "";
  1234.                 end;
  1235.         `(literals branches):
  1236.             ~ (literals (<atom> <item>...) ... (<atom> <item>...))
  1237.             ~ (branches <pattern> ... <pattern>)
  1238.             begin
  1239.             princ("{", out);
  1240.             patternToString(item[2], out);
  1241.             for pattern in cddr(item) do
  1242.                 princ(", ", out) also
  1243.                 patternToString(pattern, out);
  1244.             princ("} ", out);
  1245.             return 0;
  1246.             end;
  1247.         rewritesTo:
  1248.             ~ (rewritesTo)
  1249.             princ("->", out);
  1250.         t:
  1251.             pWarning("unknown item in a pattern: " cat item);
  1252.         end;
  1253.  
  1254.  
  1255. ~---------------------------------------------------------------------------------------~
  1256. ~            Type checkers -- callable from Plisp rules            ~
  1257. ~---------------------------------------------------------------------------------------~
  1258.  
  1259. defun identifier () =
  1260.     ~ Checks if the next thing in the input is an identifier; returns it if so.
  1261.     ~ An identifier is any symbol which is not a delimiter.  Conceptually an
  1262.     ~ identifier is like a word in English, i.e. made up of letters and digits.
  1263.     ~ The letters are the alphabet a...z, the international characters
  1264.     ~ æ Æ œ Œ ø Ø å Å ç Ç ß, the special characters ! ? _ & and any character
  1265.     ~ preceded by a back slash (\).
  1266.     ~ 'identifier' is a PLISP CONCEPT, not a Lisp data type.
  1267.  
  1268.     let (atm := peek()) =
  1269.         if symbolp(atm) and not atm.delimiter then next()
  1270.         else failure("an identifier");
  1271.  
  1272. defun aDelimiter () =
  1273.     ~ Checks if the next thing in the input is a delimiter; returns it if so.
  1274.     ~ A delimiter is any symbol which is marked with the property 'glisp::delimiter'.
  1275.     ~ Conceptually a delimiter is any character which is not a letter, digit or
  1276.     ~ white space character, e.g. @ # $ % ^ & + - * / = [ ] ( ) { } < > etc.
  1277.     ~ 'delimiter' is a PLISP CONCEPT, not a Lisp data type.
  1278.  
  1279.     let (atm := peek()) =
  1280.         if symbolp(atm) and atm.delimiter then next()
  1281.         else failure("a delimiter");
  1282.  
  1283.  
  1284. defun aNumber () =
  1285.     ~ tests if the next thing in the input is a Lisp number; returns it if so.
  1286.     ~ this is faster than calling <aType number>
  1287.  
  1288.     if numberp(peek()) then next()
  1289.     else failure("a number");
  1290.  
  1291.  
  1292. defun aString () =
  1293.     ~ tests if the next thing in the input is a Lisp string; returns it if so.
  1294.     ~ this is faster than calling <aType string>
  1295.  
  1296.     if stringp(peek()) then next()
  1297.     else failure("a string");
  1298.  
  1299.  
  1300. defun aType (typ) =
  1301.     ~ general type checker: tests if the next thing in the input is of Lisp type
  1302.     ~ 'typ'; returns it if so.
  1303.     ~ (hint) in general, specific type checking functions such as aNumber and aString
  1304.     ~ should be written whenever a type of item is checked for frequently; passing
  1305.     ~ arguments in Plisp function calls, e.g. <aType string>, is fairly inefficient.
  1306.  
  1307.     if typep(peek(), typ) then next()
  1308.     else failure("an item of type '" cat typ cat "'");
  1309.  
  1310.  
  1311. defun reservedWord () =
  1312.     ~ this is the same as 'identifier' except that it fails if the identifier is not
  1313.     ~ a reserved word in the current source language.
  1314.     ~ reserved words are identified by having the name of the language as a property,
  1315.     ~ e.g.        begin --> (mlisp t ...)
  1316.  
  1317.     let (atm := peek()) =
  1318.         if symbolp(atm) and atm.(!sourceLanguage) then next()
  1319.         else failure("a reserved word");
  1320.  
  1321.  
  1322. defun nonReservedWord () =
  1323.     ~ this is the same as 'reservedWord' except that it fails if the identifier IS
  1324.     ~ a reserved word in the current source language.
  1325.  
  1326.     let (atm := peek()) =
  1327.         if symbolp(atm)                ~ a symbol
  1328.             and not atm.delimiter        ~ and not a delimiter
  1329.             and not atm.(!sourceLanguage)    ~ and not a reserved word in the
  1330.         then next()                ~    current source language
  1331.         else failure("a non reserved-word identifier");
  1332.  
  1333.  
  1334. defun eof () =
  1335.     ~ checks if the input is exhausted; fails if it isn't
  1336.  
  1337.     if peek() eq !eof then !noValue
  1338.     else failure(!eof);
  1339.  
  1340.  
  1341. defun isNot (x) =
  1342.     ~ succeeds iff the next thing in the input is NOT x; fails if it is.
  1343.     ~ x may be any s-expression.
  1344.  
  1345.     if peek() equalp x then failure("to not find '" cat x cat "'")
  1346.     else !noValue;
  1347.  
  1348.  
  1349. ~---------------------------------------------------------------------------------------~
  1350. ~            Utility functions callable from Plisp rules            ~
  1351. ~---------------------------------------------------------------------------------------~
  1352.  
  1353. defun flush () =
  1354.     ~ deletes all the saved backtracking state, in order to reclaim space.
  1355.     ~ everything in a pattern after <flush> MUST SUCCEED, otherwise the results
  1356.     ~ are unpredictable; see Plisp.glisp and Mlisp.glisp for examples.
  1357.  
  1358.     !savedSources := nil also        ~ clear out the saved source lists
  1359.     !noValue;                ~ <flush> returns no value
  1360.  
  1361.  
  1362. defun pVariable (&optional var := identifier(), onLeft := leftSide?()) =
  1363.     ~ returns the canonical name for a Plisp variable.
  1364.     ~ if a variable is not supplied, it will read one from the input stream.
  1365.  
  1366.     canonicalName(var, onLeft);
  1367.  
  1368.  
  1369. defun lhs () =                    ~ "left hand side"
  1370.     ~ asserts that we're on the left hand side of a rule at PARSE time
  1371.  
  1372.     begin
  1373.     !varNames := nil;
  1374.         push(nil, !sideStack);            ~ (nil ...) => left hand side
  1375.     return !noValue;
  1376.     end;
  1377.  
  1378.  
  1379. defun rhs () =                    ~ "right hand side"
  1380.     ~ asserts that we're on the right hand side of a rule at PARSE time
  1381.  
  1382.     begin
  1383.     if leftSide?() then            ~ going from left to right side
  1384.         !varNames := reverse(!varNames);
  1385.     push(t, !sideStack);            ~ (t ...) => right hand side
  1386.     return !noValue;
  1387.     end;
  1388.  
  1389.  
  1390. defun phs () =                    ~ "previous hand side"
  1391.     ~ returns to the previous side of the rule we were on before the last change.
  1392.     ~ this is always paired with a call to <rhs>
  1393.  
  1394.     begin
  1395.     pop(!sideStack);            ~ restore the previous value
  1396.     if leftSide?() then            ~ going from right to left side
  1397.         !varNames := reverse(!varNames);  ~ restore the previous order
  1398.     return !noValue;
  1399.     end;
  1400.  
  1401.  
  1402. defun onLeft () =
  1403.     ~ fails unless it occurs on the left side of a rule at PARSE time
  1404.  
  1405.     if leftSide?() then !noValue
  1406.     else failure();                ~ don't supply an argument here
  1407.  
  1408.  
  1409. defun onRight () =
  1410.     ~ fails unless it occurs on the right side of a rule at PARSE time
  1411.  
  1412.     if rightSide?() then !noValue
  1413.     else failure();                ~ don't supply an argument here
  1414.  
  1415.  
  1416. defun pWarning (&rest messages) =
  1417.     ~ prints a warning message on the standard output stream (the display usually).
  1418.     ~ any number of s-expressions may be passed to 'pWarning'.
  1419.  
  1420.     begin
  1421.     `fresh-line(`*pstandard-output*);    ~ start a new line if necessary
  1422.     princ("*** Warning, ", `*pstandard-output*);
  1423.     for m in messages do
  1424.         princ(m, `*pstandard-output*);
  1425.     terpri(`*pstandard-output*);
  1426.     return !noValue;            ~ has no Plisp value
  1427.     end;
  1428.  
  1429.  
  1430. defun pError (&rest messages) =
  1431.     ~ error during pattern matching.
  1432.     ~ prints an error message on the display and breaks using the Lisp readtable.
  1433.     ~ any number of s-expressions may be passed to 'pError'.
  1434.  
  1435.     begin
  1436.     new `*readtable* := `*lisp-readtable*;
  1437.     terpri(`*perror-output*);
  1438.     printc("*** Error,", `*perror-output*);
  1439.     for m in messages do
  1440.         princ(m, `*perror-output*);
  1441.     printc("*** Input:");
  1442.     princList(rest !source, `*perror-output*);
  1443.     terpri(`*perror-output*);
  1444.     terpri(`*perror-output*);
  1445.     break();                ~ break to Lisp
  1446.     !source := xNew();            ~ when we return, clear out the input
  1447.     failure();                ~ and fail
  1448.     end;
  1449.  
  1450.  
  1451. defun checkFunction (fn) =
  1452.     ~ prints a function name on the standard output stream (the display usually).
  1453.     ~ also checks if the function already has a definition
  1454.  
  1455.     begin
  1456.     if symbolp(fn) and fboundp(fn) then
  1457.         pWarning("function redefined: ", fn) also
  1458.         !nRedefined := !nRedefined + 1
  1459.     else princAtom(fn, `*pstandard-output*);
  1460.     return !noValue;
  1461.     end;
  1462.  
  1463.  
  1464. ~---------------------------------------------------------------------------------------~
  1465. ~            Other routines available to Plisp programmers            ~
  1466. ~---------------------------------------------------------------------------------------~
  1467. ~
  1468. ~ when input is coming from a stream:
  1469. ~    !source = a headed list that always has at least one element (which is !eof
  1470. ~        at end of file)
  1471. ~    !sourceStream = the stream from which tokens are read to replenish !source.
  1472. ~ when input is coming from a list:
  1473. ~    !source = a headed list that can be xnull
  1474. ~    !sourceStream = nil
  1475.  
  1476.  
  1477. defun empty? () =
  1478.     ~ predicate: true iff the input stream is empty
  1479.  
  1480.     xNull?(!source) or cadr(!source) eq !eof;
  1481.  
  1482.  
  1483. defun peek () =
  1484.     ~ returns the next token in the input stream.
  1485.     ~ this is non-destructive; the input stream is not changed.
  1486.     ~ this and 'next' are the two basic functions for obtaining tokens from the
  1487.     ~ input stream.
  1488.  
  1489.     if empty?() then !eof
  1490.     else cadr(!source);
  1491.  
  1492.  
  1493. defun next () =
  1494.     ~ removes the next token from the input stream and returns it.
  1495.     ~ this and 'peek' are the two basic functions for obtaining tokens from the
  1496.     ~ input stream.
  1497.  
  1498.     if null !sourceStream then        ~ processing a list
  1499.         if empty?() then failure()    ~ *** should this be !eof ??
  1500.         else if !farthestTail eq cdr(!source) then
  1501.             prog1(xPop(!source), !farthestTail := cdr !source)
  1502.         else xPop(!source)
  1503.     else if cddr(!source) then        ~ reprocessing already-scanned input
  1504.         xPop(!source)
  1505.     else    begin                ~ processing a stream
  1506.         ~ must leave at least one element, so read one from the stream
  1507.         new x;
  1508.         !farthestFailure  := nil;
  1509.         !farthestFunction := nil;
  1510.         !farthestIndex    := ask(!sourceStream, currIndex());
  1511.         x := `read-preserving-whitespace(!sourceStream, nil, !eof, nil);
  1512.         !source := !source xCons x;
  1513. ~ *** kludge: always reads an s-expression after a quote mark (') ***
  1514.         if x eq '\' then
  1515.             !source := !source xCons readSExpression(!sourceStream);
  1516.         return xPop(!source);
  1517.         end;
  1518.  
  1519.  
  1520. defun nextIs? (x) =
  1521.     ~ predicate: true iff the next item in the input stream is equalp to x;
  1522.     ~ removes it if so.  x may be any s-expression.
  1523.  
  1524.     if peek() equalp x then next() also t
  1525.     else nil;
  1526.  
  1527.  
  1528. defun nextAre? (l) =
  1529.     ~ predicate: true iff the next sequence of tokens in the input stream are all
  1530.     ~ equalp to the s-expressions in the list 'l'; removes them if so.
  1531.  
  1532.     every(function(lambda (x) = nextIs?(x)), l);
  1533.  
  1534.  
  1535. defun failure (&optional message, override) =
  1536.     ~ an item in a pattern has failed to match the input.
  1537.     ~ execute a throw to the tag bound to the constant !failure.
  1538.     ~ every decision point in a pattern sets up a catch for this throw.
  1539.     ~ the item associated with the furthest point reached in the input is remembered
  1540.     ~ for later printing in an error message if necessary.
  1541.     ~ the message passed in should be a string or other value which is suitable for
  1542.     ~ appending to the string
  1543.     ~    "<function> expected "
  1544.     ~ e.g. if you want the error message to read
  1545.     ~    "<expression> expected a 'foo', but it got a 'bar' instead"
  1546.     ~ the argument to failure should be
  1547.     ~    "a 'foo', but it got a 'bar' instead"
  1548.  
  1549.     begin
  1550.     if !pTrace and !currentPlispFunction.pFullTrace and message then
  1551.         begin
  1552.         indentedPrintc("item failed: ", message);
  1553.         indentedPrintc("input: ");
  1554.         princList(rest !source, `*ptrace-output*);
  1555.         terpri(`*ptrace-output*);
  1556.         if !currentPlispFunction.pTrap then
  1557.             pbreak();
  1558.         end;
  1559.     recordMessage(message, override);
  1560.     throw(!failure, t);
  1561.     end;
  1562.  
  1563.  
  1564. defun failureValue? (value) =
  1565.     ~ does the value returned by papply represent a failure?
  1566.  
  1567.     consp(value) and first(value) eq !failure;
  1568.  
  1569.  
  1570. defun plispFunction? (fn) =
  1571.     ~ predicate: true iff 'fn' is the name of a plisp (i.e. rewrite) function
  1572.  
  1573.     symbolp(fn) and fn.pFunction;
  1574.  
  1575.  
  1576. defun leftSide? () =
  1577.     ~ predicate: true iff this is called from an item on the left side of a rule
  1578.     ~ at PARSE time
  1579.  
  1580.     not car(!sideStack);
  1581.  
  1582.  
  1583. defun rightSide? () =
  1584.     ~ predicate: true iff this is called from an item on the right side of a rule
  1585.     ~ at PARSE time
  1586.  
  1587.     car(!sideStack);
  1588.  
  1589.  
  1590. ~---------------------------------------------------------------------------------------~
  1591. ~        Utility functions of general interest to Lisp programs            ~
  1592. ~---------------------------------------------------------------------------------------~
  1593.  
  1594. defun cat (x, y) =
  1595.     ~ concatenates any two objects into a string
  1596.  
  1597.     concatenate('string, str(x), str(y));
  1598.  
  1599.  
  1600. defun neql (x, y) =
  1601.     ~ for completeness and symmetry with 'eql'
  1602.  
  1603.     not(x eql y);
  1604.  
  1605.  
  1606. defun nequal (x, y) =
  1607.     ~ for completeness and symmetry with 'equal'
  1608.  
  1609.     not(x equal y);
  1610.  
  1611.  
  1612. defun nequalp (x, y) =
  1613.     ~ for completeness and symmetry with 'equalp'
  1614.  
  1615.     not(x equalp y);
  1616.  
  1617.  
  1618. defun plist (x) =
  1619.     ~ for historical compatibility
  1620.  
  1621.     `symbol-plist(x);
  1622.  
  1623.  
  1624. defun pname (x) =
  1625.     ~ for historical compatibility
  1626.  
  1627.     `symbol-name(x);
  1628.  
  1629.  
  1630. defun printc (x, &optional stream := nil) =
  1631.     ~ analogous to 'print', but uses 'princ' instead of 'prin1'
  1632.  
  1633.     terpri(stream) also
  1634.     princ(x, stream) also
  1635.     princ(" ", stream) also
  1636.     x;
  1637.  
  1638.  
  1639. defun str (x) =
  1640.     ~ converts anything to a string
  1641.  
  1642.     if stringp(x) then x
  1643.     else if symbolp(x) then `symbol-name(x)
  1644.     else `princ-to-string(x);
  1645.  
  1646.  
  1647. ~---------------------------------------------------------------------------------------~
  1648. ~                Interface Lisp -> Plisp                    ~
  1649. ~---------------------------------------------------------------------------------------~
  1650.  
  1651. defun peval (l, &key source := 'glisp, target := nil, readtable := `*glisp-readtable*) =
  1652.     ~ Lisp -> Plisp interface.
  1653.     ~ :source is the language in which the input is written.
  1654.     ~ :target is the language being defined by the input, if any.
  1655.     ~ :readtable is the readtable to use in scanning tokens.
  1656.     ~ example: peval('(expression if a = b then c else d), :source 'mlisp)
  1657.  
  1658.     if consp(l) then
  1659.         papply(first l, rest l, :source source, :target target,
  1660.             :readtable readtable)
  1661.     else error("the argument to 'peval' must be a list: \~a", l);
  1662.  
  1663.  
  1664. defun papply (pfn, args, &key
  1665.         :source !sourceLanguage := 'glisp,
  1666.         :target !targetLanguage := nil,
  1667.         :readtable `*readtable* := `*glisp-readtable*) =
  1668.     ~ Lisp -> Plisp interface
  1669.     ~ :source is the language in which the input is written.
  1670.     ~ :target is the language being defined by the input, if any.
  1671.     ~ :readtable is the readtable to use in scanning tokens.
  1672.     ~ example: papply('glisp::expression, '(if a = b then c else d \;),
  1673.     ~                      :source 'mlisp)
  1674.  
  1675.     begin
  1676.  
  1677.     ~ set up the Plisp execution context
  1678.     new !source, !sourceStream, !farthestTail,    ~ these are bound below
  1679.         !savedSources := nil, !sourceStack := nil, !destStack := nil,
  1680.         !sideStack := nil, !varNames := nil,        
  1681.         !farthestFailure := nil, !farthestFunction := pfn, !farthestIndex := 0,
  1682.         !currentPlispFunction := pfn, !pIndent := 0;
  1683.     new value;
  1684.  
  1685.     ~ check the arguments
  1686.     if not plispFunction?(pfn) then return error(
  1687.           "the first argument to 'papply' must be the name of a Plisp function: \~a",
  1688.         pfn);
  1689.  
  1690.     ~ see where the input is coming from
  1691.     typecase args of
  1692.         begin
  1693.         list:
  1694.             !sourceStream := nil also
  1695.             !source       := xHead(args) also
  1696.             !farthestTail := rest !source;
  1697.         stream:
  1698.             !sourceStream := args also
  1699.             !source       := xHead({`read-preserving-whitespace(
  1700.                         !sourceStream, nil, !eof, nil)}) also
  1701.             !farthestTail := nil;
  1702.         otherwise:
  1703.             return error("the second argument to 'papply' must be a list "
  1704.                 cat " or a stream, not a \~a", `type-of(args));
  1705.         end;
  1706.  
  1707.     ~ execute the plisp function, picking up the input stream free
  1708.     return    if failed?(value := apply(pfn, nil)) then    ~ catch failures
  1709.             {!failure, !source,
  1710.                 "<"    cat (    if !farthestFunction then
  1711.                               `string-downcase(!farthestFunction)
  1712.                         else "an unknown function")
  1713.                     cat "> expected "
  1714.                     cat (!farthestFailure or "something"),
  1715.                 if listp(args) then !farthestTail else !farthestIndex}
  1716.         else if atom(value) or rest(value) then    ~ no values or multiple values
  1717.             value
  1718.         else first(value);        ~ a single value
  1719.     end;
  1720.  
  1721.  
  1722. defun pcall (pfn, args) =
  1723.     ~ calls a Plisp function from Lisp when the Plisp execution environment is
  1724.     ~ already set up; i.e. the Lisp function was itself called from a Plisp function
  1725.  
  1726.     begin
  1727.     new value;
  1728.     if args then                ~ are arguments being passed?
  1729.         !source := `copy-list(args) xPrepend !source;
  1730.     value := apply(pfn, nil);
  1731.     return if consp(value) then car(value) else value;
  1732.     end;
  1733.  
  1734.  
  1735. ~---------------------------------------------------------------------------------------~
  1736. ~                Stream parsing functions                ~
  1737. ~---------------------------------------------------------------------------------------~
  1738.  
  1739. defun parse (                    ~ the main Glisp parsing driver
  1740.     ifile,                    ~ the input file name
  1741.     &key    :output ofile := nil,        ~ the output file name, if any
  1742.         pretty := nil,            ~ pretty print the output?
  1743.         evaluate := t,            ~ evaluate the translation?
  1744.         asString := nil,        ~ interpret ifile as a source string?
  1745.         source := 'glisp,        ~ language in which the input is written
  1746.         target := nil,            ~ language being defined by the input
  1747.         parser := 'glispProgram,    ~ main Glisp parsing function
  1748.         readtable := `*glisp-readtable*,  ~ the readtable to use in scanning
  1749.         package := nil) =        ~ if this is part of a package
  1750.  
  1751.     begin
  1752.     new tim, value, !reservedWords := nil, !nRedefined := 0,
  1753.         `*package* :=
  1754.             if package then
  1755.                 `find-package(package) or
  1756.                     return error("no such package: " cat package)
  1757.             else `*package* ;
  1758.     if stringp(ifile) and not asString then
  1759.         announce(ifile, ofile);
  1760.     printc("----------", `*pstandard-output*);
  1761.     terpri(`*pstandard-output*);
  1762.     tim := `get-internal-run-time();
  1763.     value :=
  1764.         if null ifile then
  1765.             parseString(`read-line(t, nil, !eof, nil), parser,
  1766.                 :source source, :target target, :readtable readtable)
  1767.         else if asString and stringp(ifile) then
  1768.             parseString(ifile, parser,
  1769.                 :source source, :target target, :readtable readtable)
  1770.         else if stringp(ifile) then
  1771.             parseFile(ifile, parser,
  1772.                 :source source, :target target, :readtable readtable)
  1773.         else if listp(ifile) then
  1774.             parseList(ifile, parser,
  1775.                 :source source, :target target, :readtable readtable)
  1776.         else if streamp(ifile) then
  1777.             parseStream(ifile, parser,
  1778.                 :source source, :target target, :readtable readtable)
  1779.         else return error("the first argument to 'parse' must be a string, "
  1780.             cat "list, or stream, not a \~a: \~a", `type-of(ifile), ifile);
  1781.     tim := (`get-internal-run-time() - tim) / `internal-time-units-per-second;
  1782.     `fresh-line(`*pstandard-output*);
  1783.     princ("----------", `*pstandard-output*);
  1784.     if value eq !failure then
  1785.         return !failure;
  1786.     printc(round(float(tim)) cat " seconds translation time", `*pstandard-output*);
  1787.     printc(!nRedefined cat " functions redefined", `*pstandard-output*);
  1788.     if ofile then
  1789.         printTranslation(value, ofile, pretty)
  1790.     else if evaluate then
  1791.         begin
  1792.         terpri(`*pstandard-output*);
  1793.         printc("Evaluating the translation...", `*pstandard-output*);
  1794.         for x in value do eval(x);
  1795.         end;
  1796.     terpri(`*pstandard-output*);
  1797.     terpri(`*pstandard-output*);
  1798.     return    if not evaluate then value    ~ just return the translation
  1799.         else if package then `*package*
  1800.         else 'done;
  1801.     end;
  1802.  
  1803.  
  1804. defun parseFile (filename, parser,
  1805.         &key source := 'glisp, target := nil, readtable := `*glisp-readtable*) =
  1806.     ~ parses a file written in the source language
  1807.     ~ e.g. parseFile("mlisp.glisp", 'glispProgram, :source 'glisp, :target 'mlisp)
  1808.  
  1809.     begin
  1810.     new value;
  1811.     `with-open-file(
  1812.         `(stream (merge-pathnames filename)
  1813.             :direction        :input
  1814.             :element-type        'character
  1815.             :if-does-not-exist    :error),
  1816.         value := papply(parser, stream, :source source, :target target,
  1817.                 :readtable readtable),
  1818.         if failureValue?(value) then
  1819.             explainError(value, stream) also
  1820.             value := !failure);
  1821.     return value;
  1822.     end;
  1823.  
  1824.  
  1825. defun parseString (s, parser,
  1826.         &key source := 'glisp, target := nil, readtable := `*glisp-readtable*) =
  1827.     ~ parses a string written in the source language
  1828.     ~ e.g. parseString("a -> b", 'rule)
  1829.  
  1830.     begin
  1831.     new value;
  1832.     `with-input-from-string(
  1833.         `(stream s),
  1834.         value := papply(parser, stream, :source source, :target target,
  1835.                 :readtable readtable),
  1836.         if failureValue?(value) then
  1837.             explainError(value, s, ask(stream, `ccl::end)) also
  1838.             value := !failure);
  1839.     return value;
  1840.     end;
  1841.  
  1842.  
  1843. defun parseList (l, parser,
  1844.         &key source := 'glisp, target := nil, readtable := `*glisp-readtable*) =
  1845.     ~ parses a list written in the source language
  1846.     ~ e.g. parseList('(a - > b), 'rule)
  1847.  
  1848.     begin
  1849.     new value;
  1850.     value := papply(parser, l, :source source, :target target, :readtable readtable);
  1851.     if failureValue?(value) then
  1852.         explainError(value, l) also
  1853.         value := !failure;
  1854.     return value;
  1855.     end;
  1856.  
  1857.  
  1858. defun parseStream (s, parser,
  1859.         &key source := 'glisp, target := nil, readtable := `*glisp-readtable*) =
  1860.     ~ parses a stream written in the source language; this is the same as parseList
  1861.     ~ e.g. parseStream(s, 'rule)
  1862.  
  1863.     parseList(s, parser, :source source, :target target, :readtable readtable);
  1864.  
  1865.  
  1866. defun reparse (name, filename, &key
  1867.         source := 'glisp,
  1868.         target := nil,
  1869.         parser := 'reparsePlispFunction,
  1870.         locater := 'locatePlispFunction,
  1871.         readtable := `*glisp-readtable*,
  1872.         package := nil) =
  1873.     ~ translates a single Plisp function in a file.
  1874.     ~ this is useful during debugging to keep from having to reparse an entire file
  1875.     ~ every time you make a change.
  1876.     ~ the definition of what is to be translated is provided by the "parser" Plisp
  1877.     ~ function, which defaults to 'reparsePlispFunction'.
  1878.     ~ :source is the language in which the input is to be interpreted.
  1879.     ~ :target is the language, if any, being defined by the input.
  1880.     ~ the user may supply a "locater" function to skip to where the item begins;
  1881.     ~ such a function must take two arguments: the name of the item (a symbol)
  1882.     ~ and the stream to search, and return true iff it successfully finds it.
  1883.     ~ e.g. reparse('foo, "mlisp.gli", :source 'mlisp, :parser 'mlispFunction,
  1884.     ~    :locater 'locateMlispFunction, :package `:glisp)
  1885.  
  1886.     begin
  1887.     new value, !reservedWords := nil, !nRedefined := 0,
  1888.         `*package* :=
  1889.             if package then
  1890.                 `find-package(package) or
  1891.                     return error("no such package: " cat package)
  1892.             else `*package* ;
  1893.     if package then
  1894.         name := intern(pname(name));    ~ translate to that package's symbol
  1895.     `with-open-file(
  1896.         `(stream (merge-pathnames filename)
  1897.             :direction        :input
  1898.             :element-type        'character
  1899.             :if-does-not-exist    :error),
  1900.         ~ skip to where the item begins
  1901.         if apply(locater, {name, stream, readtable}) then
  1902.             begin
  1903.             value := papply(parser, stream, :source source, :target target,
  1904.                     :readtable readtable);
  1905.             if failureValue?(value) then
  1906.                 explainError(value, stream)
  1907.             else    begin
  1908.                 if target then
  1909.                     addReservedWords(target, !reservedWords);
  1910.                 eval(value);
  1911.                 end;
  1912.             end
  1913.         else printc("Item not found: " cat name, `*pstandard-output*));
  1914.     return `*package*;
  1915.     end;
  1916.  
  1917.  
  1918. defun locatePlispFunction (name, stream, `*readtable*) =
  1919.     ~ quickly skips to the beginning of a Plisp function; works only on file streams
  1920.  
  1921.     begin
  1922.     new x := '\;, index, foundit;
  1923.     until (x eq '\; or x eq '\- or x eq !eof)
  1924.         and case x of
  1925.             begin
  1926.             \; :            ~ ; name = ...
  1927.                 begin
  1928.                 index := `file-position(stream);
  1929.                 foundit :=  read(stream, nil, !eof, nil) eq name
  1930.                     and read(stream, nil, !eof, nil) member '(\= \();
  1931.                 `file-position(stream, index);
  1932.                 return foundit;
  1933.                 end;
  1934.             \- :            ~ -Plisp- name = ...
  1935.                 begin
  1936.                 index := `file-position(stream);
  1937.                 foundit :=  read(stream, nil, !eof, nil) eq 'Plisp
  1938.                     and read(stream, nil, !eof, nil) eq '\-
  1939.                     and (index := `file-position(stream))
  1940.                     and read(stream, nil, !eof, nil) eq name
  1941.                     and read(stream, nil, !eof, nil) member '(\= \();
  1942.                 `file-position(stream, index);
  1943.                 return foundit;
  1944.                 end;
  1945.             otherwise:        ~ end of file
  1946.                 t;
  1947.             end
  1948.     do x := read(stream, nil, !eof, nil);
  1949.     return x neq !eof;
  1950.     end;
  1951.  
  1952.  
  1953. defun printTranslation (l, filename, pretty) =
  1954.     ~ prints or pretty prints all of the elements in the list 'l' to a file
  1955.  
  1956.     begin
  1957.     new `*print-abbreviate-quote* := nil;    ~ don't turn (quote x) into 'x
  1958.     terpri(`*pstandard-output*);
  1959.     filename := `merge-pathnames(filename);
  1960.     printc(if pretty then "Pretty printing" else "Printing", `*pstandard-output*);
  1961.     princ("the translation on " cat namestring(filename) cat "...",
  1962.         `*pstandard-output*);
  1963.     `with-open-file(
  1964.         `(stream filename
  1965.             :direction        :output
  1966.             :element-type        'character
  1967.             :if-exists        :supersede
  1968.             :if-does-not-exist    :create),
  1969.         for x in l do
  1970.             begin
  1971.             if pretty then pprint(x, stream)
  1972.             else print(x, stream);
  1973.             terpri(stream);
  1974.             end);
  1975.     end;
  1976.  
  1977.  
  1978. defun explainError (value, stream, &optional endPos := nil) =
  1979.     ~ explains the meaning of an error returned by 'papply'
  1980.     ~ value = (!failure !source errorMessage !farthestIndex/Tail)
  1981.  
  1982.     let (!source := value[2], !sourceStream, !sourceStack, !currentPlispFunction) =
  1983.         failed?(pError(value[3], ":  ",
  1984.             if listp(value[4]) then
  1985.                 if value[4] then first value[4]
  1986.                 else "end of the input"
  1987.             else if endPos then subseq(stream, value[4], endPos)
  1988.             else if consp(stream) then ""
  1989.             else `file-position(stream, value[4]) also
  1990.                 `read-line(stream, nil, !eof, nil)));
  1991.  
  1992.  
  1993. defun announce (ifile, ofile) =
  1994.     ~ prints on the screen the name of the file that's about to be translated
  1995.  
  1996.     begin
  1997.     terpri(`*pstandard-output*);
  1998.     princ(`pathname-name(ifile), `*pstandard-output*);    ~ don't use printc here
  1999.     if `pathname-type(ifile) then
  2000.         princ("." cat `pathname-type(ifile), `*pstandard-output*);
  2001.     if  ofile then
  2002.         princ(" -> " cat `pathname-name(ofile), `*pstandard-output*) also
  2003.         if `pathname-type(ofile) then
  2004.             princ("." cat `pathname-type(ofile), `*pstandard-output*);
  2005.     princ("...", `*pstandard-output*);
  2006.     end;
  2007.  
  2008.  
  2009. defobfun currIndex (`*stream*) () =
  2010.     `ccl::index;
  2011.  
  2012.  
  2013. defobfun currIndex (`ccl::*file-stream*) () =
  2014.     `file-position(self());
  2015.